#pragma once
#include "IOObject.hpp"

namespace zzz {
class IOFile
{
public:
  template<typename T>
  static bool SaveFileA(const string &filename, const T &obj) {
    ZLOGV << "Saving file " << filename << "...\n";
    return IOFileA<T>::SaveFile(filename, obj);
  }
  template<typename T>
  static bool LoadFileA(const string &filename, T &obj) {
    ZLOGV << "Loading file " << filename << "...\n";
    return IOFileA<T>::LoadFile(filename, obj);
  }
  template<typename T>
  static bool SaveFileB(const string &filename, const T &obj) {
    ZLOGV << "Saving file " << filename << "...\n";
    return IOFileB<T>::SaveFile(filename, obj);
  }
  template<typename T>
  static bool LoadFileB(const string &filename, T &obj) {
    ZLOGV << "Loading file " << filename << "...\n";
    return IOFileB<T>::LoadFile(filename, obj);
  }
  template<typename T>
  static bool SaveFileR(const string &filename, const T &obj) {
    ZLOGV << "Saving file " << filename << "...\n";
    return IOFileR<T>::SaveFile(filename, obj);
  }
  template<typename T>
  static bool LoadFileR(const string &filename, T &obj) {
    ZLOGV << "Loading file " << filename << "...\n";
    return IOFileR<T>::LoadFile(filename, obj);
  }
};

template<typename T>
class IOFileA
{
public:
  static bool SaveFile(const string &filename, const T &obj) {
    ofstream fo(filename);
    if (!fo.good()) return false;
    IOObject<T>::WriteFileA(fo, obj);
    fo.close();
    return true;
  }
  static bool LoadFile(const string &filename, T &obj) {
    ifstream fi(filename);
    if (!fi.good()) return false;
    IOObject<T>::ReadFileA(fi, obj);
    fi.close();
    return true;
  }
};

template<typename T>
class IOFileB
{
public:
  static bool SaveFile(const string &filename, const T &obj) {
    FILE *fp = fopen(filename.c_str(), "wb");
    if (!fp) return false;
    IOObject<T>::WriteFileB(fp, obj);
    fclose(fp);
    return true;
  }
  static bool LoadFile(const string &filename, T &obj) {
    FILE *fp = fopen(filename.c_str(), "rb");
    if (!fp) return false;
    IOObject<T>::ReadFileB(fp, obj);
    fclose(fp);
    return true;
  }
};

const int IOFILER_MAGIC = 1025;

template<typename T>
class IOFileR
{
public:
  static bool SaveFile(const string &filename, const T &obj) {
    RecordFile rf;
    rf.SaveFileBegin(filename);
    IOObject<T>::WriteFileR(rf, IOFILER_MAGIC, obj);
    rf.SaveFileEnd();
    return true;
  }
  static bool LoadFile(const string &filename, T &obj) {
    RecordFile rf;
    rf.LoadFileBegin(filename);
    IOObject<T>::ReadFileR(rf, IOFILER_MAGIC, obj);
    rf.LoadFileEnd();
    return true;
  }
};

};  // namespace zzz